import axios, { AxiosRequestConfig, AxiosResponse, AxiosStatic } from 'axios'
import { Modal } from 'antd'
import { queryString, createTraceId } from '@/utils/util'
const isDev = process.env.NODE_ENV === 'development';
const Cookies = require('js-cookie')
import { getQueryString } from '@/utils/util';

// 需要延迟请求到登录后再使用
const isAuthrictedPromise = new Promise<void>(resolve => {
  (window as any).enResolve = () => {
    (window as any).enResolve = () => {}
    resolve()
  }
})

interface RequestOptions extends AxiosRequestConfig {
  // 请求前缀
  prefix?: string;
  jsonp?: boolean;
  callback?: string;
}
interface RequestExtConfig {
  authorization: boolean;
  customErrorHandle: boolean;
  timeout: number;
}

const dftExtConfig: RequestExtConfig = {
  timeout: 15000,
  authorization: true,
  customErrorHandle: false
}

const bffAfterRequest = (
  res: AxiosResponse,
  o: RequestOptions = {},
  ext: Partial<RequestExtConfig> = {}
) => {
  const { customErrorHandle } = { ...dftExtConfig, ...ext }

  const statusCode = Number(res.status)
  const data = res.data || {}
  let code = data.code

  // 更新本地 token
  if (res.headers && (res.headers['Set-Authorization'] || res.headers['set-authorization'])) {
    const token = (res.headers['Set-Authorization'] as string || res.headers['set-authorization'] as string).split(' ')[1] || '';
    if (token) {
      localStorage.setItem('token', token);
    }
  }

  if (data.retCode || data.retCode === 0) code = data.retCode

  if (statusCode === 200 && Number(code) === 0) {
    return Promise.resolve(data)
  }

  // 不为 200
  if (statusCode !== 200) {
    console.error('服务端错误，', res, o)
    if (customErrorHandle) {
      return Promise.resolve({ code: 3, error: ['服务器异常'] })
    }
    Modal.error({ title: '提示', content: '服务器繁忙中，请稍后再试！' })
  }

  // bff 业务错误
  if (code > 0) {
    // console.error('请求错误，', res, o)
    // 聚合接口部分服务错误，照常返回并提示错误
    if (code === 1) {
      return Promise.resolve(data)
    }
    if (customErrorHandle) {
      return Promise.resolve(data)
    } else {
      let errTip = data.msg || data.error.join(';') || '服务器繁忙中，请稍后再试！'
      if (errTip === 'Deadline Exceeded') {
        errTip = '接口请求超时，请稍后重试！'
      }
      // const errTip = res.data.msg || res.statusText || '服务器繁忙中，请稍后再试！'
      // console.error('服务器异常，', data, o)
      Modal.error({ title: '错误提示', content: errTip })
      return Promise.reject(data)
    }
  }

  // bff 异常
  if (code < 0) {
    console.error('服务器异常，', res, o)
    Modal.error({ title: '错误提示', content: '服务器繁忙中，请稍后再试！' })
    return Promise.reject(data)
  }
}

/**
 * 对 axios 进行能力增强
 *
 * @param {AxiosStatic} axios
 */
const enhanceAxios = (axios: AxiosStatic) => {
  return async (_options: RequestOptions): Promise<AxiosResponse | any> => {
    const {
      jsonp,
      prefix,
      callback = _options.params.callback || _options.callback || 'callback',
      ...options
    } = _options

    if (jsonp) {
      const target = document.getElementsByTagName('script')[0] || document.head
      const script = document.createElement('script')
      const query = queryString(options.params || {})
      script.src = `${options.baseURL}${options.url}${query}`;
      (target.parentNode as any).insertBefore(script, target)
      return new Promise(resolve => {
        (window as any)[callback] = (res: any) => {
          resolve(res)
          if (script.parentNode) script.parentNode.removeChild(script)
          delete window[callback]
        }
      })
    }

    return axios(options)
  }
}

const request = async (
  api: string,
  o: RequestOptions = {},
  ext: Partial<RequestExtConfig> = {}
) => {
  const {
    authorization,
    customErrorHandle,
    // timeout
  } = { ...dftExtConfig, ...ext }
  const timeout = o.timeout || dftExtConfig.timeout;
  const baseURL = '/baseRequestUrl';
  const token = localStorage.getItem('token');
  const traceId = createTraceId();
  const orgcode = isDev ? 'gzminjieadmin_test' : Cookies.get('env_orgcode') || Cookies.get('intelligence_orgcode') || Cookies.get('loginOrgName');

  const requestOptions = Object.assign(o, {
    url: api,
    baseURL,
    withCredentials: true,
    data: { ...o.data },
    params: { ...(o.params || {}) },
    method: o.method || 'GET',
    jsonp: o.jsonp || false,
    timer: setTimeout(() => {}, 0),
    headers: {
      'Authorization': `Bearer ${token}`,
      'Accept': 'application/json, text/plain, application/javascript */*',
      'Content-Type': 'application/json',
      'orgcode': orgcode,
      'Trace-Id': traceId,
      'token': getQueryString('token') || '',
      'activity-id': getQueryString('activity_id') || '',
      'secret': getQueryString('secret') || '',
    },
  })

  // 超时提示
  requestOptions.timer = setTimeout(() => {
    Modal.warning({
      title: '超时提示',
      content: '接口请求超时，请稍后重试！',
    })
  }, timeout)

  let res
  try {
    res = await enhanceAxios(axios)(requestOptions)
  } catch (err: any) {
    res = err.response
  } finally {
  }
  clearTimeout(requestOptions.timer)
  if (!o.jsonp) {
    return bffAfterRequest(res, o, { authorization, customErrorHandle })
  }
  return res
}

const requestAuthorizationWrapper = async (api: string, o: RequestOptions = {}, ext: Partial<RequestExtConfig> = {}) => {
  const extConfig = { ...dftExtConfig, ...ext }
  if (extConfig.authorization) {
    await isAuthrictedPromise
  }
  return request(api, o, extConfig)
}

export default requestAuthorizationWrapper
